<?php

namespace app\api\middleware;

use app\Request;
use think\facade\Log;

/**
 * 验证登录及权限
 */
class Auth
{
    // 方法白名单
    private $_MethodWhiteList = []; // controllerName/methodName

	public function handle(Request $request, $next) {
        $res = $this->_checkSign($request);
        if(!$res) {
            return $this->setError();
        }

        return $next($request);
	}

    private function _checkSign(Request $request) {
        // get方式不进行签名验证
        if($request->isGet()) {
            return true;
        }

        // 方法白名单内的接口不进行签名验证
        $path = $request->pathinfo();
        if(in_array($path, $this->_MethodWhiteList)) {
            return true;
        }

        // 测试环境不进行签名验证
        if(env('ENV') == 'dev') {
            //return true;
        }

        $signRequest = $request->header('sign');

        if(!$signRequest) {
            Log::error('签名验证失败,未提交签名');
            $this->_logError($request);
            return false;
        }

        $timestamp = $request->header('timestamp');
        if(!$timestamp) {
            Log::error('签名验证失败,未提交时间戳');
            $this->_logError($request);
            return false;
        }
        if(($timestamp / 1000) < time() - 10) {
            Log::error('签名验证失败,时间戳过期:' . $timestamp);
            $this->_logError($request);
            return false;
        }
        $strPrivate = env('api_sign', 'api_sign');

        // 获取原始 json
        $str = $request->getInput();
        $str .= $timestamp . $strPrivate;
        $base64 = base64_encode($str);
        $sign = md5($base64);

        if($sign != $signRequest) {
            $this->_logError($request);
            Log::error('签名验证失败 exe: ' . $sign .' req:'. $signRequest);
            Log::error('str: '.$str);
            Log::error('base64: ' . $base64);
            return false;
        }
        return true;
    }

    private function _logError(Request $request) {
        Log::error('=============');
        Log::error(sprintf("url: %s", $request->url()));
        Log::error(sprintf("header:%s", json_encode($request->header())));
        Log::error(sprintf("token:%s", $request->header('token', '')));
        Log::error(sprintf("ip:%s", $request->ip()));
        Log::error(sprintf("param:%s", json_encode($request->param())));
    }

    public function setError() {
        $data = \app\api\extend\Response::setError('网络错误,请重试.');
        return json($data)->code(500);
    }

}